#pragma once
#include <string>
#include <vector>
#include <functional>

#ifdef WIN32
#ifdef util_EXPORTS
#define UTIL_API __declspec(dllexport)
#else
#define UTIL_API __declspec(dllimport)
#endif
#else
#define UTIL_API
#endif
namespace Util {
class IniParserImpl;
class UTIL_API IniParser
{
public:
    /**
     * @brief 初始化类，初始化过程中加载所有键值对到缓存,
     * 如果两个实例同时操作一个文件，可能会存在缓存不一致的问题，暂时没有好的解决方法
     * 
     * @param path 配置文件路径

     * @exception 无
     */
    IniParser(const char* path);
    ~IniParser();

    enum ini_errcode
    {
        WRITE_ERR = -7,  // 在将属性树转换为INI或写入文件时出错;
        VALUE_TYPE_ERR = -6,  // 数据类型转换失败;读取array时，该错误可能会覆盖VALUE_RANGE_ERR错误,返回最后发生的错误;尽可能使用读取到的值
        INI_VECTOR_FORMAT_ERR = -5,  // 读取的vector时，未识别到{};全部使用默认值
        DEFAULT_LEN_NOT_MACTH = -4,  // 读取的vector元素数量与默认值的元素数量不匹配;该错误一定会覆盖VALUE_RANGE_ERR和VALUE_TYPE_ERR错误;尽可能使用读取到的值
        VALUE_RANGE_ERR = -3,  // 超出范围;vector中，仅超过阈值的元素使用默认值,该错误可能会覆盖VALUE_TYPE_ERR错误,返回最后发生的错误;尽可能使用读取到的值
        READ_ERR = -2,         // 一般出现于:未找到节点;;全部使用默认值
        FILE_ERR = -1,         // 一般出现于:打开INI文件错误(文件不存在,权限等);INI中存在重复的key;全部使用默认值
        OK = 0,                // 无错误;
    };

    /**
     * @brief 读取int32类型的配置
     * 
     * @param exp 配置路径，如读取ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 返回配置的值
     * @param defaultVal 读取错误或值超出范围时的val返回的值，注意其错误原因也会体现在函数返回值中
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int get(std::string exp, int32_t& val, int32_t defaultVal);

    /**
     * @brief 更新缓存中int32类型的配置
     * 
     * @param exp 配置路径，如更新缓存中ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 更新缓存中配置的值
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int set(std::string exp, int32_t val);

    /**
     * @brief 读取int32类型的配置
     * 
     * @param exp 配置路径，如读取ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 返回配置的值
     * @param defaultVal 读取错误或值超出范围时的val返回的值，注意其错误原因也会体现在函数返回值中
     * @param min 最小值，闭区间
     * @param max 最小值，闭区间
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int get(std::string exp, int32_t& val, int32_t defaultVal, int32_t min, int32_t max);

    /**
     * @brief 更新缓存中int32数组类型的配置
     * 
     * @param exp 配置路径，如更新缓存中ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 更新缓存中配置的值
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int set(std::string exp, std::vector<int32_t> val);

    /**
     * @brief 读取int32数组类型的配置，如{0,1,2,3}
     * 
     * @param exp 配置路径，如读取ZUC下的POSE配置，则给ZUC.POSE
     * @param val 返回配置的值
     * @param defaultVal 读取错误或值超出范围时的val返回的值，注意其错误原因也会体现在函数返回值中
     * @param min 最小值，闭区间
     * @param max 最小值，闭区间
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int get(std::string exp, std::vector<int32_t>& val, std::vector<int32_t> def, int32_t min = INT32_MIN, int32_t max = INT32_MAX);

    /**
     * @brief 读取double类型的配置
     * 
     * @param exp 配置路径，如读取ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 返回配置的值
     * @param defaultVal 读取错误或值超出范围时的val返回的值，注意其错误原因也会体现在函数返回值中
     * @param min 最小值，允许误差1.0E-10
     * @param max 最小值，允许误差1.0E-10
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int get(std::string exp, double& val, double defaultVal, double min, double max);

    /**
     * @brief 更新缓存中double类型的配置
     * 
     * @param exp 配置路径，如更新缓存中ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 更新缓存中配置的值
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int set(std::string exp, double val);

    /**
     * @brief 读取double数组类型的配置，如{0.0,1.1,2.2,3.3}
     * 
     * @param exp 配置路径，如读取ZUC下的POSE配置，则给ZUC.POSE
     * @param val 返回配置的值
     * @param defaultVal 读取错误或值超出范围时的val返回的值，注意其错误原因也会体现在函数返回值中
     * @param min 最小值，允许误差1.0E-10
     * @param max 最小值，允许误差1.0E-10
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int get(std::string exp, std::vector<double>& val, std::vector<double> def, double min, double max);

    /**
     * @brief 更新缓存中double数组类型的配置
     * 
     * @param exp 配置路径，如更新缓存中ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 更新缓存中配置的值
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int set(std::string exp, std::vector<double> val);

    /**
     * @brief 读取bool类型的配置，
     * 
     * @param exp 配置路径，如读取ZUC下的POSE配置，则给ZUC.POSE
     * @param val 返回配置的值
     * @param defaultVal 读取错误或值超出范围时的val返回的值，注意其错误原因也会体现在函数返回值中
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int get(std::string exp, bool& val, bool defaultVal);

    /**
     * @brief 更新缓存中bool类型的配置
     * 
     * @param exp 配置路径，如更新缓存中ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 更新缓存中配置的值
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int set(std::string exp, bool val);

    /**
     * @brief 读取bool数组类型的配置，如{True,1,0,4},
     * 
     * @param exp 配置路径，如读取ZUC下的POSE配置，则给ZUC.POSE
     * @param val 返回配置的值
     * @param defaultVal 读取错误或值超出范围时的val返回的值，注意其错误原因也会体现在函数返回值中
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int get(std::string exp, std::vector<bool>& val, std::vector<bool> defaultVal);

    /**
     * @brief 更新缓存中bool数组类型的配置
     * 
     * @param exp 配置路径，如更新缓存中ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 更新缓存中配置的值
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int set(std::string exp, std::vector<bool> val);

    /**
     * @brief 读取string类型的配置
     * 
     * @param exp 配置路径，如读取ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 返回配置的值
     * @param defaultVal 读取错误或值超出范围时的val返回的值，注意其错误原因也会体现在函数返回值中
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int get(std::string exp, std::string& val, std::string defaultVal);

    /**
     * @brief 读取string数组类型的配置,如{just, always,keep ,ama zing},得到["just"," always","keep ","ama zing"]
     * 
     * @param exp 配置路径，如读取ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 返回配置的值
     * @param defaultVal 读取错误或值超出范围时的val返回的值，注意其错误原因也会体现在函数返回值中
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int get(std::string exp, std::vector<std::string>& val, std::vector<std::string> defaultVal);

    /**
     * @brief 更新缓存中int32/double/bool类型的配置
     * 
     * @param exp 配置路径，如更新缓存中ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 更新缓存中配置的值
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int set(std::string exp, std::string val);

    /**
     * @brief 更新缓存中string数组类型的配置
     * 
     * @param exp 配置路径，如更新缓存中ZUC下的DEBUG配置，则给ZUC.DEBUG
     * @param val 配置的值
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int set(std::string exp, std::vector<std::string> val);

    /**
     * @brief 执行写入文件,将缓存的数据写入磁盘
     * 
     * @param 无
     * @return int 若为0则通过，否则返回错误码
     * @exception 无
     */
    int save_ini();

    bool is_valid();
    inline const char* path() const { return _path.c_str(); }

private:
    std::string _path;
    IniParserImpl* _impl;
};
}  // namespace Util
